//////////////////////////////////////////////////////////////////////////////
//	Copyright 2011 Alex Leffelman
//	
//	Licensed under the Apache License, Version 2.0 (the "License");
//	you may not use this file except in compliance with the License.
//	You may obtain a copy of the License at
//	
//	http://www.apache.org/licenses/LICENSE-2.0
//	
//	Unless required by applicable law or agreed to in writing, software
//	distributed under the License is distributed on an "AS IS" BASIS,
//	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//	See the License for the specific language governing permissions and
//	limitations under the License.
//////////////////////////////////////////////////////////////////////////////

package com.zhuxulin.midi.event.meta;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.zhuxulin.midi.event.MidiEvent;
import com.zhuxulin.midi.util.ReadVarLen;
/**
 * FF 58 event
 * @author ZhuXulin
 *
 */
public class TimeSignature extends MetaEvent {

	public static final int METER_EIGHTH = 12;
	public static final int METER_QUARTER = 24;
	public static final int METER_HALF = 48;
	public static final int METER_WHOLE = 96;
	
	public static final int DEFAULT_METER = METER_QUARTER;
	public static final int DEFAULT_DIVISION = 8;
	
	private int mNumerator;
	private int mDenominator;
	private int mMeter;
	private int mDivision;
	
	public TimeSignature() {
		this(0, 0, 4, 4, DEFAULT_METER, DEFAULT_DIVISION);
	}
	
	public TimeSignature(long tick, long delta, int num, int den, int meter, int div) {
		super(tick, delta, MetaEvent.TIME_SIGNATURE, new ReadVarLen(4));
		
		setTimeSignature(num, den, meter, div);
	}
	
	public void setTimeSignature(int num, int den, int meter, int div) {
		mNumerator = num;
		mDenominator = log2(den);
		mMeter = meter;
		mDivision = div;
	}
	
	public int getNumerator() {
		return mNumerator;
	}
	public int getDenominatorValue() {
		return mDenominator;
	}
	public int getRealDenominator() {
		return (int)Math.pow(2, mDenominator);
	}
	public int getMeter() {
		return mMeter;
	}
	public int getDivision() {
		return mDivision;
	}

	@Override
	protected int getEventSize() {
		return 7;
	}
	
	@Override
	public void writeToFile(OutputStream out) throws IOException {
		super.writeToFile(out);
		
		out.write(4);
		out.write(mNumerator);
		out.write(mDenominator);
		out.write(mMeter);
		out.write(mDivision);
	}
	@Override
	public byte[] getCmd() {
		cmd = new byte[] { (byte) 0xFF, 0x58, 0x04, (byte) mNumerator,
				(byte) mDenominator, (byte) mMeter, (byte) mDivision };
		return cmd;
	}
	public static TimeSignature parseTimeSignature(long tick, long delta, InputStream in) throws IOException {
		
		in.read();		// Size = 4
		
		int num = in.read();
		int den = in.read();
		int met = in.read();
		int fps = in.read();
		
		den = (int)Math.pow(2, den);
		
		return new TimeSignature(tick, delta, num, den, met, fps);
	}
	
	private int log2(int den) {
		switch(den) {
		case 2:
			return 1;
		case 4:
			return 2;
		case 8:
			return 3;
		case 16:
			return 4;
		case 32:
			return 5;
		}
		return 0;
	}
	
	@Override
	public String toString() {
		return super.toString() + " " + mNumerator + "/" + getRealDenominator();
	}
	
	@Override
	public int compareTo(MidiEvent other) {
		
		if(mTick != other.getTick()) {
			return mTick < other.getTick() ? -1 : 1;
		}
		if(mDelta.getValue() != other.getDelta()) {
			return mDelta.getValue() < other.getDelta() ? 1 : -1;
		}
		
		if(!(other instanceof TimeSignature)) {
			return 1;
		}
		
		TimeSignature o = (TimeSignature)other;

		if(mNumerator != o.mNumerator) {
			return mNumerator < o.mNumerator ? -1 : 1;
		}
		if(mDenominator != o.mDenominator) {
			return mDenominator < o.mDenominator ? -1 : 1;
		}
		return 0;
	}
}
